package crack3d;

import java.util.ArrayList;

import fem2.AbstractStructuralCrackDemo;
import fem2.Block;
import fem2.Constraint;
import fem2.Debugger;
import fem2.Element;
import fem2.Force;
import fem2.MaterialModel;
import fem2.Mesh;
import fem2.MeshGenerator;
import fem2.MeshUtilities;
import fem2.Model;
import fem2.Node;
import fem2.analysis.Analysis;
import fem2.element.StructuralElement;
import fem2.enu.EchoLevelType;
import fem2.enu.State;
import fem2.material.StVenantKirchhoffMM;
import fem2.material.cohesive_law.CohesiveLaw;
import fem2.observer.StressObserverForSDAElement;
import fem2.observer.TimeStepObserver;
import fem2.pre_and_post.GidMeshGenerator;
import fem2.strategies.ArcLengthSolutionStrategyWithSphereConstraint;
import fem2.strategies.Strategy;

public abstract class AbstractDoubleNotchedSpecimenUsingSDAElement extends
		AbstractStructuralCrackDemo {

	public AbstractDoubleNotchedSpecimenUsingSDAElement() {
		projectDir = "/home/hbui/kratos_janosch";
		projectName = "double-notched-specimen.gid";
	}

	@Override
	public Mesh createMesh() {
		String fn = projectDir + '/' + projectName + '/' + meshFileName;
		MeshGenerator mg = new GidMeshGenerator(fn);
		Mesh mesh = mg.getMesh(3);
		return mesh;
	}

	@Override
	public Model createConditions(Model m) {
		Mesh mesh = m.getMesh();

		Constraint c = new Constraint(false, false, false);

		ArrayList<Node> bottom = MeshUtilities.seekNodesOnSurface(mesh, 0, 0, 1, 0);

		mesh.addConstraint(c, bottom);

		Node n1 = MeshUtilities.seekNode(mesh, 0, 0, 140);
		Node n2 = MeshUtilities.seekNode(mesh, 50, 0, 140);
		Node n3 = MeshUtilities.seekNode(mesh, 50, 25, 140);
		Node n4 = MeshUtilities.seekNode(mesh, 0, 25, 140);

		double P = 100;
		Force f1 = new Force(n1, 0, 0, P / 4);
		Force f2 = new Force(n2, 0, 0, P / 4);
		Force f3 = new Force(n3, 0, 0, P / 4);
		Force f4 = new Force(n4, 0, 0, P / 4);
		m.addLoad(f1);
		m.addLoad(f2);
		m.addLoad(f3);
		m.addLoad(f4);

		return m;
	}

	@Override
	public MaterialModel createMaterial(Model m) {
		double E = 1e4;
		double nu = 0.1;
		double t = 1.0;
		State ss = State.THREE_DIMENSIONAL;
		MaterialModel mm = new StVenantKirchhoffMM(E, nu, t, 0, ss);
		return mm;
	}

	public MaterialModel createMaterial2(Model m) {
		double E = 1e6;
		double nu = 0.1;
		double t = 1.0;
		State ss = State.THREE_DIMENSIONAL;
		MaterialModel mm = new StVenantKirchhoffMM(E, nu, t, 0, ss);
		return mm;
	}

	@Override
	public Model createModel() {

		Mesh mesh = createMesh();

		mesh.setNumberOfFields(mesh.getDimension());

		Model m = new Model(mesh);

		MaterialModel mm = createMaterial(m);
		MaterialModel mm2 = createMaterial2(m);

		CohesiveLaw cl = createCohesiveLaw(m);

		for (int i = 0; i < mesh.countBlocks(); i++) {
			Block b = mesh.getBlock(i);
			double[] c = b.computeCenter();
			Element e;
			if (c[2] > 120 || c[2] < 20) {
				// e = createElement(b, mm2, cl);
				e = new StructuralElement(b, mm2);
			} else {
				e = createElement(b, mm, cl);
			}
			m.addElement(e);
		}

		m = createConditions(m);

		return m;
	}

	@Override
	public void addObservers(final Model m, final Strategy s, TimeStepObserver o) {
		addFundamentalObservers(m, s, o);
		addObserversForCrackProblem(m, s, o);

		s.addObserver(new StressObserverForSDAElement(m));

		// XYSourceObserver xyo = new XYSourceObserver() {
		//
		// Node n1 = MeshUtilities.seekNodeNearest(m.getMesh(), 654.0, 0);
		// Node n2 = MeshUtilities.seekNodeNearest(m.getMesh(), 668.0, 0);
		//
		// @Override
		// public void fireTimeStepFinished() {
		// double[] u1 = n1.getUHatLocal();
		// double[] u2 = n2.getUHatLocal();
		// double du = LinAlg.diffNorm2(u1.length, u1, u2);
		// double lambda = s.getCurrentTimeStep();
		// setData(du, lambda);
		// }
		//
		// };
		//
		// s.addObserver(xyo);
		// s.addObserver(new XYGraphicalObserver(xyo, "lambda-distance plot"));
	}

	@Override
	public void run(double[] sArray) {
		Model m = createModel();

		Analysis an = new Analysis(m);

		Strategy s = new ArcLengthSolutionStrategyWithSphereConstraint(m, sArray, 0.0);

		s.setEchoLevel(EchoLevelType.OUTPUT, EchoLevelType.AUX1);

		an.setStrategy(s);

		addObservers(m, s, (TimeStepObserver) s.addObserver(new TimeStepObserver()));

		an.run();

		// postProcess(m);

		Debugger.warn("Analysis completed");
	}
}
